package util;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

import model.Ant;
import model.Cell;
import model.Point;
import model.Resource;
import model.Space2D;

public class SpaceUtilities {

	/*
	public static Space2D initSpace(Space2D space) {
		
		Point p1 = new Point(0,0);
		Point p2 = new Point(7,3);
		Point p3 = new Point(4,5);
		Point p4 = new Point(7,9);
		
		try {
			Ant ant1 = new Ant(space, p1);		
			Ant ant2 = new Ant(space, p2);
			Resource r1 = new Resource(space, p1, "r1");
			Resource r2 = new Resource(space, p3, "r2");
			Resource r3 = new Resource(space, p4, "r3");
			
			space.addAnt(ant1);
			space.addAnt(ant2);
			space.addResource(r1);
			space.addResource(r2);
			space.addResource(r3);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return space;		
	}
	*/
	
	public static Point getRandomPoint(int dim) {
		Point p = null;
		
		Random random = new Random();
		p = new Point(random.nextInt(dim), random.nextInt(dim));
		
		return p; 
	}
	
	public static void initRandomAnt(Space2D space, boolean activatePheromone, double orientationCoef, double pheromoneCoef, String attractionField) {
		Point p = null;
		
		ArrayList antList = space.getListAnts();
		boolean repeatedPos = true;
		while(repeatedPos) {
			//get a rqndom point for this resource
			p = getRandomPoint(space.getDimension());
			//check if this point is already in the list
			Ant tmpAnt = null;
			Point tmpPoint = null;
			boolean findPos = true;
			for(int j = 0; j < antList.size(); j++) {
				tmpAnt = (Ant)antList.get(j);
				tmpPoint = tmpAnt.getLocation();
				if(tmpPoint.equals(p)) {
					findPos = false;
					break;
				}
			}
			if(findPos) {
				repeatedPos = false;
			}
		}
		//add the generated random ant to the list
		try {
			Ant ant = new Ant(space, p, orientationCoef, pheromoneCoef, attractionField);
			ant.setPheromoneActivated(activatePheromone);
			space.addAnt(ant);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/*
	public static void initSpecifiedAnt(Space2D space, Point p,  boolean activatePheromone) {
		
		ArrayList antList = space.getListAnts();
		boolean repeatedPos = true;
		while(repeatedPos) {
			//check if this point is already in the list
			Ant tmpAnt = null;
			Point tmpPoint = null;
			boolean findPos = true;
			for(int j = 0; j < antList.size(); j++) {
				tmpAnt = (Ant)antList.get(j);
				tmpPoint = tmpAnt.getLocation();
				if(tmpPoint.equals(p)) {
					findPos = false;
					break;
				}
			}
			if(findPos) {
				repeatedPos = false;
			}
		}
		//add the generated random ant to the list
		try {
			Ant ant = new Ant(space, p);
			ant.setPheromoneActivated(activatePheromone);
			space.addAnt(ant);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	*/
	
	@SuppressWarnings("finally")
	public static Point getFreePosition(Space2D space) {
		Point p = null;
		
		try {
			ArrayList resourceList = space.getListRes();
			boolean repeatedPos = true;
			while(repeatedPos) {
				//get a rqndom point for this resource
				p = getRandomPoint(space.getDimension());
				//check if this point is already in the list
				Resource tmpRes = null;
				Point tmpPoint = null;
				boolean findPos = true;
				for(int j = 0; j < resourceList.size(); j++) {
					tmpRes = (Resource)resourceList.get(j);
					tmpPoint = tmpRes.getLocation();
					if(tmpPoint.equals(p)) {
						findPos = false;
						break;
					}
				}
				if(findPos) {
					repeatedPos = false;
				}
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			return p;
		}
		
	}
	
	public static void initResourcesAtRandom(int nbResType1, int nbResType2, int nbResType3, Space2D space) {
		
		//add a type1 resource
		for(int i = 0; i < nbResType1; i++) {
			try {
				space.addResource(new Resource(space, getFreePosition(space), Resource.Resource_Type_1));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		//add a type2 resource
		for(int i = 0; i < nbResType2; i++) {
			try {
				space.addResource(new Resource(space, getFreePosition(space), Resource.Resource_Type_2));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		
		//add a type3 resource
		for(int i = 0; i < nbResType3; i++) {
			try {
				space.addResource(new Resource(space, getFreePosition(space), Resource.Resource_Type_3));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public static void colorResource(Graphics g, Resource res, int gridSize) {
		String type = res.getType();		
		Point p = res.getLocation();
		int x = p.getX();
		int y = p.getY();
		if(type.equals(Resource.Resource_Type_1)) {
			g.setColor(Color.RED);
			g.fillRect(x*gridSize + 4, y*gridSize + 4, gridSize/2+1, gridSize/2+1);
		} else if(type.equals(Resource.Resource_Type_2)) {
			g.setColor(Color.BLUE);
			g.fillOval((int)((x+0.3)*gridSize)-1, (int)((y+0.3)*gridSize)-1, gridSize/2+2, gridSize/2+2);
		} else if(type.equals(Resource.Resource_Type_3)) {
			g.setColor(Color.GREEN);
			int[] xs = new int[3];
			int[] ys = new int[3];
			//length of each edge : gridSize / 2
			int edgeWidth = (int)(0.8*gridSize);
			int triHeight = (int)(1.732*edgeWidth/2) + 4;
			xs[0] = x*gridSize + edgeWidth/2 + 2;
			xs[1] = x*gridSize + (gridSize-edgeWidth)/2;
			xs[2] = (x+1)*gridSize - (gridSize-edgeWidth)/2;
			ys[0] = y*gridSize + (gridSize - triHeight)/2 + 1;
			ys[1] = y*gridSize + triHeight;
			ys[2] = ys[1];
			g.fillPolygon(xs, ys, 3);
		}
	}
	
	public static void drawAnt(Graphics g, Point p, int gridSize) {
		int x = p.getX();
		int y = p.getY();
		
		//System.out.println(System.getProperty("user.dir"));
		Image img = new ImageIcon("src/view/ant.gif").getImage();
		g.drawImage(img, x*gridSize + 1, y*gridSize + 1, gridSize - 1, gridSize - 1, null);
	}
	
	public static void removeAnt(Graphics g, Space2D space, Point p, int gridSize) {
		int x = p.getX();
		int y = p.getY();
		
		Resource res = space.getCell(p).getResource();
			
		g.setColor(Color.WHITE);
		g.fillRect(x*gridSize + 1, y*gridSize + 1, gridSize - 1, gridSize - 1);
		
		if(res != null) {
			String type = res.getType();		

			if(type.equals(Resource.Resource_Type_1)) {
				g.setColor(Color.RED);
				g.fillRect(x*gridSize + 4, y*gridSize + 4, gridSize/2+1, gridSize/2+1);
			} else if(type.equals(Resource.Resource_Type_2)) {
				g.setColor(Color.BLUE);
				g.fillOval((int)((x+0.3)*gridSize)-1, (int)((y+0.3)*gridSize)-1, gridSize/2+2, gridSize/2+2);
			} else if(type.equals(Resource.Resource_Type_3)) {
				g.setColor(Color.GREEN);
				int[] xs = new int[3];
				int[] ys = new int[3];
				//length of each edge : gridSize / 2
				int edgeWidth = (int)(0.8*gridSize);
				int triHeight = (int)(1.732*edgeWidth/2) + 4;
				xs[0] = x*gridSize + edgeWidth/2 + 2;
				xs[1] = x*gridSize + (gridSize-edgeWidth)/2;
				xs[2] = (x+1)*gridSize - (gridSize-edgeWidth)/2;
				ys[0] = y*gridSize + (gridSize - triHeight)/2 + 1;
				ys[1] = y*gridSize + triHeight;
				ys[2] = ys[1];
				g.fillPolygon(xs, ys, 3);
			}
		}		
	}
	
	public static void removeResource(Graphics g, Space2D space, Resource resource, int gridSize) {
		Point p = resource.getLocation();
		int x = p.getX();
		int y = p.getY();
		
		Ant ant = space.getCell(p).getAnt();
			
		g.setColor(Color.WHITE);
		g.fillRect(x*gridSize + 1, y*gridSize + 1, gridSize - 1, gridSize - 1);
		
		if(ant != null) {
			Image img = new ImageIcon("src/view/ant.gif").getImage(); 
			g.drawImage(img, x*gridSize + 1, y*gridSize + 1, gridSize - 1, gridSize - 1, null);
		}		
	}
	
	public static void drawTrace(Graphics g, Point p1, Point p2, int gridSize, Color c) {

		int x1 = p1.getX() * gridSize + gridSize/2;
		int y1 = p1.getY() * gridSize + gridSize/2;
		int x2 = p2.getX() * gridSize + gridSize/2;
		int y2 = p2.getY() * gridSize + gridSize/2;

		g.setColor(c);
		((Graphics2D)g).setStroke(new BasicStroke(2));
		g.drawLine(x1, y1, x2, y2);
		((Graphics2D)g).setStroke(new BasicStroke(1));
	}
	
	public static void markPoint(Graphics2D g, Point p, Color c, int unitLength) {
		int x = p.getX();
		int y = p.getY();
		g.setColor(c);
		g.setStroke(new BasicStroke(3));
		g.drawRect(x*unitLength, y*unitLength, unitLength, unitLength);
		g.setStroke(new BasicStroke(1));
	}
	
	public static Color[] initColorArray(Color[] cs) {
		Vector<Color> csv = new Vector<Color>();
		
		csv.add(new Color(0, 0, 128));
		csv.add(new Color(0, 128, 0));
		csv.add(new Color(0, 128, 128));
		csv.add(new Color(0, 255, 128));
		csv.add(new Color(0, 255, 255));
		
		csv.add(new Color(128, 0, 0));
		csv.add(new Color(128, 0, 128));
		csv.add(new Color(128, 0, 255));
		csv.add(new Color(128, 128, 0));
		csv.add(new Color(128, 128, 128));
		csv.add(new Color(128, 128, 0));
		csv.add(new Color(128, 255, 128));
		csv.add(new Color(128, 255, 255));
		
		csv.add(new Color(255, 0, 128));
		csv.add(new Color(255, 0, 255));
		csv.add(new Color(255, 128, 0));
		csv.add(new Color(255, 128, 128));
		csv.add(new Color(255, 128, 0));
		csv.add(new Color(255, 255, 128));
		csv.add(new Color(255, 255, 0));
		
		Random ran = new Random();
		int preDefinedColorsSize = csv.size();
		for(int i = 0; i < cs.length; i++ ) {
			int c = ran.nextInt(csv.size());
			cs[i] = csv.get(c);
			if(cs.length < preDefinedColorsSize) csv.remove(c);
		}
		return cs;
	}
	
	public static void initPreDefinedAttractionZone(Graphics g, Space2D space) {
		//set of points which are seen as the attraction zone
		/*int maxNbAttrPoint = space.getDimension() * space.getDimension() / 3;
		
		if(space.getDimension() == 50) {	
		}*/
		//TODO initialize with the predefined attraction points set if it exist
	}
	
	public static Point transformCoordinate(java.awt.Point jp, int unitWidth) {
		int x = (int)(jp.getX() / (double)unitWidth);
		int y = (int)(jp.getY() / (double)unitWidth);
		
		return new Point(x, y);
	}
	
	/*public static Point transformCoordinate(java.awt.Point jp, int unitWidth, Point p) {
		int x = (int)(jp.getX() / (double)unitWidth);
		int y = (int)(jp.getY() / (double)unitWidth);
		
		p.setX(x);
		p.setY(y);
		return p;
	}*/
	
	public static void colorAttractionPoints(Graphics g, int gridSize, HashMap<String, Point> attrPoints) {
		Point p = null;
		Iterator<Map.Entry<String, Point>> it = attrPoints.entrySet().iterator();
		while(it.hasNext()) {
			Map.Entry<String, Point> entry = (Map.Entry<String, Point>)it.next();
			p = entry.getValue();
			int x = p.getX();
			int y = p.getY();
			g.setColor(Color.GRAY);
			g.fillRect(x*gridSize+1, y*gridSize+1, gridSize-1, gridSize-1);
		}
	}
	
	public static void colorPheromonePoints(Graphics g, int gridSize, Space2D space) {
		/*
		 * suppose that pheromone level from (240, 240, 255)(light, pheromone = 1) 
		 * to (141, 141, 255)(dark, pheromone = 100) : 100 level
		 */
		ArrayList<Cell> pheromoneCells = space.getListCellsWithPheromone();
		Cell currentCell = null;
		Color c = null;
		for(int i = 0; i < pheromoneCells.size(); i++) {
				currentCell = pheromoneCells.get(i);
				int phromoneLevel = currentCell.getPheromone();
				if(phromoneLevel > 100) phromoneLevel = 100;
				if(phromoneLevel > 0) {
					c = new Color(241-phromoneLevel, 241-phromoneLevel, 255);
					g.setColor(c);
					//TODO need a list of all the cells with pheromone and their coordinates to color them 
					//ex. HashMap(Point, Cell).
				}
		}
	}
}